﻿using System;
using System.Security.Cryptography;

namespace IntoNails.Infrastructure.Security
{
    public class RandomPasswordGenerator
    {
        private const int DefaultMinPasswordLength = 5;
        private const int DefaultMaxPasswordLength = 12;
        private const string PasswordCharsLcase = "abcdefgijkmnopqrstwxyz";
        private const string PasswordCharsUcase = "ABCDEFGHJKLMNPQRSTWXYZ";
        private const string PasswordCharsNumeric = "123456789";
        private const string PasswordCharsSpecial = "*$-+?_&=!%{}/";

        public static string Generate()
        {
            return Generate(DefaultMinPasswordLength, DefaultMaxPasswordLength);
        }
        public static string Generate(int length)
        {
            return Generate(length, length);
        }

        public static string Generate(int minLength, int maxLength)
        {
            if (minLength <= 0 || maxLength <= 0 || minLength > maxLength)
            {
                return string.Empty;
            }

            char[][] array = new char[][]
                                 {
                                     PasswordCharsLcase.ToCharArray(),
                                     PasswordCharsUcase.ToCharArray(),
                                     PasswordCharsNumeric.ToCharArray(),
                                     PasswordCharsSpecial.ToCharArray()
                                 };

            int[] array2 = new int[array.Length];
            for (int i = 0; i < array2.Length; i++)
            {
                array2[i] = array[i].Length;
            }

            int[] array3 = new int[array.Length];
            for (int j = 0; j < array3.Length; j++)
            {
                array3[j] = j;
            }

            byte[] array4 = new byte[4];

            RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
            rngCryptoServiceProvider.GetBytes(array4);

            int seed = (array4[0] & 127) << 24 | array4[1] << 16 | array4[2] << 8 | array4[3];

            Random random = new Random(seed);
            char[] array5;

            array5 = minLength < maxLength ? new char[random.Next(minLength, maxLength + 1)] : new char[minLength];

            int num = array3.Length - 1;
            for (int k = 0; k < array5.Length; k++)
            {
                int num2 = num == 0 ? 0 : random.Next(0, num);
                int num3 = array3[num2];
                int num4 = array2[num3] - 1;
                int num5 = num4 == 0 ? 0 : random.Next(0, num4 + 1);

                array5[k] = array[num3][num5];

                if (num4 == 0)
                {
                    array2[num3] = array[num3].Length;
                }
                else
                {
                    if (num4 != num5)
                    {
                        char c = array[num3][num4];
                        array[num3][num4] = array[num3][num5];
                        array[num3][num5] = c;
                    }

                    array2[num3]--;
                }

                if (num == 0)
                {
                    num = array3.Length - 1;
                }
                else
                {
                    if (num != num2)
                    {
                        int num6 = array3[num];
                        array3[num] = array3[num2];
                        array3[num2] = num6;
                    }

                    num--;
                }
            }

            return new string(array5);
        }
    }
}
